package com.rookie.im.server.handler;

import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.rookie.im.codec.pack.LoginPack;
import com.rookie.im.codec.proto.Message;
import com.rookie.im.domain.enums.Command;
import com.rookie.im.server.domain.model.UserSession;
import com.rookie.im.domain.utils.Constants;
import com.rookie.im.server.utils.RabbitManager;
import com.rookie.im.server.utils.RedisManager;
import com.rookie.im.server.utils.SessionSocketHolder;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;

@Slf4j
public class ServerHandler extends SimpleChannelInboundHandler<Message> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Message message) throws Exception {
        log.info(""+message);
        int command = message.getMessageHead().getCommand();
        if (command == Command.LOGIN.getCommand()) {
            handleLogin(ctx.channel(), message);
        } else if (command == Command.LOGOUT.getCommand()) {
            handleLogout(ctx.channel());
        } else {
            RabbitManager.publish(message);
        }
    }

    private static void handleLogout(Channel channel) {
        String userId = (String) channel.attr(AttributeKey.valueOf(Constants.UserId)).get();
        int appId = (int) channel.attr(AttributeKey.valueOf(Constants.AppId)).get();
        int clientType = (int) channel.attr(AttributeKey.valueOf(Constants.ClientType)).get();
        String imei = (String) channel.attr(AttributeKey.valueOf(Constants.Imei)).get();

        SessionSocketHolder.removeUserSession(appId, clientType, userId, imei);

        RedissonClient redissonClient = RedisManager.getRedissonClient();
        RMap<String, String> map = redissonClient.getMap(appId + Constants.RedisConstants.UserSessionConstants + userId);
        String key = clientType + ":" + imei;
        map.remove(key);
        log.info("LOGOUT: " + key);
    }

    private static void handleLogin(Channel channel, Message message) {
        LoginPack loginPack = JSONObject.parseObject(JSONObject.toJSONString(message.getMessagePack()), new TypeReference<LoginPack>() {}.getType());
        int appId = message.getMessageHead().getAppId();
        int clientType = message.getMessageHead().getClientType();
        String userId = loginPack.getUserId();
        String imei = message.getMessageHead().getImei();

        channel.attr(AttributeKey.valueOf(Constants.UserId)).set(loginPack.getUserId());
        channel.attr(AttributeKey.valueOf(Constants.AppId)).set(appId);
        channel.attr(AttributeKey.valueOf(Constants.ClientType)).set(clientType);
        channel.attr(AttributeKey.valueOf(Constants.Imei)).set(imei);

        SessionSocketHolder.createUserSession(appId, clientType, userId, imei, channel);

        UserSession userSession = new UserSession(appId, clientType, userId, imei, 1, null);
        RedissonClient redissonClient = RedisManager.getRedissonClient();
        RMap<String, String> map = redissonClient.getMap(appId + Constants.RedisConstants.UserSessionConstants + userId);
        String key = clientType + ":" + imei;
        map.put(key, JSONObject.toJSONString(userSession));
        log.info("LOGIN: " + key);
    }
}